package com.fgba.express.util;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.fgba.express.comm.exception.BizException;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

/**
 * 获取Bean对象的帮助函数
 */
@Component
public class BeanContextUtil implements ApplicationContextAware
{
	private final static Object locker = new Object();

	private volatile static ApplicationContext applicationContext;

	/**
	 * tryGetApplicationContext()和getApplicationContext()方法区别：tryGetApplicationContext()方法获取上下文对象，可能返回null,
	 * 但是不会终止程序执行；getApplicationContext()获取上下文对象，返回null会抛出异常，终止程序执行；
	 * 
	 * @return
	 */
	public static ApplicationContext tryGetApplicationContext()
	{
		return BeanContextUtil.applicationContext;
	}

	/**
	 * 该方法获取上下文对象，如果返回null,会抛出异常，终止程序执行
	 * 
	 * @return
	 */
	public static ApplicationContext getApplicationContext()
	{
		if (BeanContextUtil.applicationContext == null)
		{
			throw new BizException("BeanContextUtil>Invoke getApplicationContext() return null.");
		}
		return applicationContext;
	}

	public static Object getBean(String name)
	{
		return BeanContextUtil.getApplicationContext().getBean(name);
	}

	public static <T> T getBean(Class<T> clz)
	{
		return BeanContextUtil.getApplicationContext().getBean(clz);
	}

	public static <T> List<T> getBeans(Class<T> clz)
	{
		Map<String, T> beanMap = BeanContextUtil.getApplicationContext().getBeansOfType(clz);

		return new ArrayList<>(beanMap.values());
	}

	public static <T> Boolean containsBean(Class<T> clz)
	{
		String[] beans = BeanContextUtil.getApplicationContext().getBeanNamesForType(clz);
		return beans.length > 0;
	}

	public static Boolean containsBean(String beanName)
	{
		return BeanContextUtil.getApplicationContext().containsBean(beanName);
	}

	public static boolean containsEnvironmentProperty(String key)
	{
		return BeanContextUtil.getBean(Environment.class).containsProperty(key);
	}


	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
	{
		if (BeanContextUtil.applicationContext != null)
		{
			return;
		}

		synchronized (BeanContextUtil.locker)
		{
			if (BeanContextUtil.applicationContext == null)
			{
				BeanContextUtil.applicationContext = applicationContext;
			}
		}
	}
}